home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / utils / elmalias.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-16  |  12.3 KB  |  512 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: elmalias.c,v 5.2 1993/05/16 20:55:32 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.2 $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *             Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: elmalias.c,v $
  17.  * Revision 5.2  1993/05/16  20:55:32  syd
  18.  * fix elmalias bug
  19.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  20.  *
  21.  * Revision 5.1  1993/04/12  02:09:29  syd
  22.  * Initial Checkin
  23.  *
  24.  *
  25.  ******************************************************************************/
  26.  
  27. /*
  28.  * elmalias - Elm alias database access.
  29.  *
  30.  * This utility will display information from the Elm user and system
  31.  * alias databases.  It will expand alias names specified on the command
  32.  * line and display the alias value.  If an item on the command line is
  33.  * not a valid alias, then it's value is returned.  If no names are
  34.  * specified on the command line then all alises are displayed.  Output
  35.  * is formatted by either a user-defined format specifier or one of a
  36.  * number of predefined specifications.  The default output format
  37.  * displays just the alias value.
  38.  *
  39.  * The format specifiers are:
  40.  *
  41.  *    %a    alias (the alias name)
  42.  *    %l    last_name
  43.  *    %n    name
  44.  *    %c    comment
  45.  *    %v    address (the alias value)
  46.  *    %t    type (Person, Group, or Unknown)
  47.  *
  48.  * In the case that a command line argument does not correspond to
  49.  * an alias, then %a and %v will evaluate to the argument value and
  50.  * all other items will be empty.
  51.  *
  52.  * Printf-like field widths may be used, e.g. "%-20.20a".  Conditionals
  53.  * are bracketed by question marks.  For example "?n(%n)?" means format
  54.  * "(%n)" if the "name" is defined, otherwise produce no output.  Some
  55.  * backslash sequences (e.g. "\t" == tab) are recognized.  Any other
  56.  * characters are displayed as is.
  57.  *
  58.  * Example:
  59.  *    $ elmalias -f "alias %a is address \"%v\" ?n(%n)?" chip
  60.  *    alias chip is address "chip@chinacat.unicom.com" (Chip Rosenthal)
  61.  *
  62.  * Synopsis:
  63.  *    elmalias [-aensuvV] [-f format] [alias ...]
  64.  *
  65.  * Options:
  66.  *    -a    Display alias name.  Equivalent to -f "%-20.20a %v".
  67.  *    -e    Fully expand alias values.
  68.  *    -f fmt    User-specified output format.
  69.  *    -n    Display name.  Equivalent to -f "%v?n (%n)?".
  70.  *    -r    Complain about arguments that are not valid aliases.
  71.  *    -s    Consult system-wide alias file.
  72.  *    -u    Consult user-specific alias file.
  73.  *    -v    Verbose output.  Equivalent to -f "%-20.20a %v?n (%n)?".
  74.  *    -V    Babble about *everything* we known about.
  75.  *
  76.  * If neither -s or -u are specified, then the default is to search
  77.  * both alias files.
  78.  */
  79.  
  80. #include "elmutil.h"
  81. #include "ndbz.h"
  82. #include "s_elmalias.h"
  83.  
  84. /*
  85.  * Maximum number of alias files we can consult.
  86.  */
  87. #define MAXDB        2    /* user and system alias files        */
  88.  
  89. /*
  90.  * These are used by the "dbz" routines.
  91.  */
  92. #ifdef DEBUG
  93. int debug = 0;
  94. FILE *debugfile = stderr;
  95. #endif
  96.  
  97. char *Progname;
  98.  
  99. /*
  100.  * "aliasdb" library routines.
  101.  */
  102. extern struct alias_rec *fetch_alias();
  103. extern char *next_addr_in_list();
  104.  
  105. /*
  106.  * Local procedures.
  107.  */
  108. DBZ *open_user_aliases(), *open_system_aliases();
  109. struct alias_rec *make_dummy_rec();
  110. void exp_print_alias(), print_alias();
  111. char *sel_alias_mem();
  112.  
  113.  
  114. void usage_error()
  115. {
  116.     fprintf(stderr, catgets(elm_msg_cat, ElmaliasSet, ElmaliasUsage,
  117.     "usage: %s [-aenrsuvV] [-f format] [alias ...]\n"), Progname);
  118.     exit(1);
  119.     /*NOTREACHED*/
  120. }
  121.  
  122.  
  123. /*ARGSUSED*/
  124. void malloc_fail_handler(proc, size)
  125. char *proc;
  126. unsigned size;
  127. {
  128.     fprintf(stderr, catgets(elm_msg_cat, ElmaliasSet, ElmaliasOutOfMemory,
  129.     "%s: out of memory [could not allocate %d bytes]\n"), Progname, size);
  130.     exit(1);
  131.     /*NOTREACHED*/
  132. }
  133.  
  134.  
  135. main(argc, argv)
  136. int argc;
  137. char *argv[];
  138. {
  139.     char *out_fmt;        /* output printing format        */
  140.     int do_user_alias;        /* TRUE to examine user alias file    */
  141.     int do_system_alias;    /* TRUE to examine system alias file    */
  142.     int do_expand;        /* TRUE to recursively expand aliases    */
  143.     int do_complain;        /* TRUE to insist args are valid aliases*/
  144.     int numdb;            /* number of alias files to consult    */
  145.     DBZ *dblist[MAXDB+1];    /* NULL terminated list of files    */
  146.     struct alias_rec *ar;    /* scratch ptr to expansion of curr name*/
  147.     int d, i;
  148.     extern int optind;
  149.     extern char *optarg;
  150.  
  151.     /*
  152.      * Initialize.
  153.      */
  154. #ifdef I_LOCALE
  155.     setlocale(LC_ALL, "");
  156. #endif
  157.     elm_msg_cat = catopen("elm2.4", 0); /* parlez vous francais?    */
  158.     safe_malloc_fail_handler =    /* install procedure to trap errors in    */
  159.     malloc_fail_handler;    /*   the safe_malloc() routines        */
  160.     Progname = argv[0];        /* program name for diag messages    */
  161.     do_user_alias = FALSE;    /* indicate the user hasn't selected    */
  162.     do_system_alias = FALSE;    /*   any alias files (yet)        */
  163.     do_expand = FALSE;        /* do not recursively expand groups    */
  164.     do_complain = FALSE;    /* allow non-aliases on cmd line    */
  165.     out_fmt = "%v";        /* default is to just show alias value    */
  166.     numdb = 0;            /* no alias files opened yet        */
  167.  
  168.     /*
  169.      * Crack command line options.
  170.      */
  171.     while ((i = getopt(argc, argv, "aef:nrsuvV")) != EOF) {
  172.     switch (i) {
  173.     case 'a':            /* show alias name and value    */
  174.         out_fmt = "%-20.20a %v";
  175.         break;
  176.     case 'e':            /* recursively expand aliases    */
  177.         do_expand = TRUE;
  178.         break;
  179.     case 'f':            /* user-specified format    */
  180.         out_fmt = optarg;
  181.         break;
  182.     case 'n':            /* show alias value and fullname*/
  183.         out_fmt = "%v?n (%n)?";
  184.         break;
  185.     case 'r':            /* insist args are valid aliases*/
  186.         do_complain = TRUE;
  187.         break;
  188.     case 's':            /* use system-wide alias file    */
  189.         do_system_alias = TRUE;
  190.         break;
  191.     case 'u':            /* use per-user alias file    */
  192.         do_user_alias = TRUE;
  193.         break;
  194.     case 'v':            /* verbose output format    */
  195.         out_fmt = "%-20.20a %v?n (%n)?";
  196.         break;
  197.     case 'V':            /* show the user's life story    */
  198.         out_fmt = "\
  199. Alias:\t\t%a\n\
  200.   Address:\t%v\n\
  201.   Type:\t\t%t\n\
  202. ?n  Name:\t\t%n\n?\
  203. ?l  Last Name:\t%l\n?\
  204. ?c  Comment:\t%c\n?\
  205. ";
  206.         break;
  207.     default:
  208.         usage_error();
  209.         /*NOTREACHED*/
  210.     }
  211.     }
  212.  
  213.     /*
  214.      * If user didn't request specific alias files then use them all.
  215.      */
  216.     if (!do_system_alias && !do_user_alias)
  217.     do_system_alias = do_user_alias = TRUE;
  218.  
  219.     /*
  220.      * Open up the alias files we need to access, in the order of priority.
  221.      */
  222.     if (do_user_alias && (dblist[numdb] = open_user_aliases()) != NULL)
  223.     ++numdb;
  224.     if (do_system_alias && (dblist[numdb] = open_system_aliases()) != NULL)
  225.     ++numdb;
  226.     dblist[numdb] = NULL;
  227.  
  228.     /*
  229.      * If no names specified on command line then dump all alias files..
  230.      */
  231.     if (optind == argc) {
  232.     if (do_expand) {
  233.         fprintf(stderr, catgets(elm_msg_cat, ElmaliasSet,
  234.         ElmaliasCannotSpecifyExpand,
  235.         "%s: cannot specify \"-e\" when dumping all aliases\n"),
  236.         Progname);
  237.         exit(1);
  238.     }
  239.     for (d = 0 ; dblist[d] != NULL ; ++d) {
  240.         /* assumes file pointer left at first key immediately after open */
  241.         while ((ar = fetch_alias(dblist[d], (char *)NULL)) != NULL) {
  242.         print_alias(out_fmt, ar);
  243.         (void) free((malloc_t)ar);
  244.         }
  245.     }
  246.     exit(0);
  247.     }
  248.  
  249.     /*
  250.      * Expand each name on the command line.
  251.      */
  252.     for (i = optind ; i < argc ; ++i) {
  253.  
  254.     /*
  255.      * Try each of the alias files for a match.
  256.      */
  257.     ar = NULL;
  258.     for (d = 0 ; dblist[d] != NULL ; ++d) {
  259.         if ((ar = fetch_alias(dblist[d], argv[i])) != NULL)
  260.         break;
  261.     }
  262.  
  263.     /*
  264.      * Print the result.
  265.      */
  266.     if (ar == NULL) {
  267.         if (do_complain) {
  268.         fprintf(stderr, catgets(elm_msg_cat, ElmaliasSet,
  269.             ElmaliasUnknownAlias, "%s: \"%s\" is not a known alias\n"),
  270.             Progname, argv[i]);
  271.         exit(1);
  272.         }
  273.         ar = make_dummy_rec(argv[i]);
  274.         print_alias(out_fmt, ar);
  275.     } else if (do_expand && (ar->type & GROUP)) {
  276.         exp_print_alias(dblist[d], out_fmt, ar);
  277.     } else {
  278.         print_alias(out_fmt, ar);
  279.     }
  280.  
  281.     (void) free((malloc_t)ar);
  282.  
  283.     }
  284.  
  285.     exit(0);
  286.     /*NOTREACHED*/
  287. }
  288.  
  289.  
  290. DBZ *open_system_aliases()
  291. {
  292.     return dbz_open(system_data_file, O_RDONLY, 0);
  293. }
  294.  
  295.  
  296. DBZ *open_user_aliases()
  297. {
  298.     char *home, *fname;
  299.     DBZ *db;
  300.     extern char *getenv();
  301.  
  302.     if ((home = getenv("HOME")) == NULL) {
  303.     fprintf(stderr, catgets(elm_msg_cat, ElmaliasSet,
  304.         ElmaliasCannotDetermineHome,
  305.         "%s: cannot determine your HOME directory\n"), Progname);
  306.     exit(1);
  307.     }
  308.     fname = (char *)safe_malloc(strlen(home) + 1 + strlen(ALIAS_DATA) + 1);
  309.     (void) strcat(strcat(strcpy(fname, home), "/"), ALIAS_DATA);
  310.     db = dbz_open(fname, O_RDONLY, 0);
  311.     (void) free((malloc_t)fname);
  312.     return db;
  313. }
  314.  
  315.  
  316. /*
  317.  * Cobble up an alias record structure to hold some address info.
  318.  */
  319. struct alias_rec *make_dummy_rec(val)
  320. char *val;
  321. {
  322.     struct alias_rec *ar;
  323.     ar = (struct alias_rec *) safe_malloc(sizeof(struct alias_rec));
  324.     ar->status = 0;
  325.     ar->alias = val;
  326.     ar->last_name = "";
  327.     ar->name = "";
  328.     ar->comment = "";
  329.     ar->address = val;
  330.     ar->type = 0;
  331.     ar->length = 0;
  332.     return ar;
  333. }
  334.  
  335.  
  336. /*
  337.  * Recursively expand out a list of addresses and print the expansions.
  338.  */
  339. void exp_print_alias(db, fmt, ar)
  340. DBZ *db;
  341. char *fmt;
  342. struct alias_rec *ar;
  343. {
  344.     char *abuf;        /* list of addresses we can scribble upon    */
  345.     char *acurr;    /* pointer to current address within "abuf"    */
  346.     char *anext;    /* pointer to next address within "abuf"    */
  347.     struct alias_rec *ar0;
  348.  
  349.     /*
  350.      * Create a copy of this address we can scribble upon.
  351.      */
  352.     anext = abuf = safe_strdup(ar->address);
  353. #ifdef lint
  354.     *abuf = '\0'; /* shutup set but not used complaint */
  355. #endif
  356.  
  357.     /*
  358.      * Go through all of the addresses and expand them out.
  359.      */
  360.     while ((acurr = next_addr_in_list(&anext)) != NULL) {
  361.     if ((ar0 = fetch_alias(db, acurr)) == NULL)
  362.         ar0 = make_dummy_rec(acurr);
  363.     if (ar0->type & GROUP)
  364.         exp_print_alias(db, fmt, ar0);
  365.     else
  366.         print_alias(fmt, ar0);
  367.     (void) free((malloc_t)ar0);
  368.     }
  369.  
  370.     (void) free((malloc_t)abuf);
  371. }
  372.  
  373.  
  374. /*
  375.  * Print out alias information according to a format specification.
  376.  */
  377. void print_alias(fmt, ar)
  378. char *fmt;
  379. struct alias_rec *ar;
  380. {
  381.     char pfmt[64];        /* buffer to hold "%m.ns" formats    */
  382.     int in_conditional;        /* TRUE if in middle of cond expression    */
  383.     int print_enab;        /* TRUE if OK to print output        */
  384.     char *s;
  385.     int n, c;
  386.  
  387.     print_enab = TRUE;
  388.     in_conditional = FALSE;
  389.  
  390.     while (*fmt != '\0') {
  391.  
  392.     switch (*fmt) {
  393.  
  394.     /*
  395.      * Formatted output.
  396.      */
  397.     case '%':
  398.  
  399.         /*
  400.          * Extract the "%m.n" portion of the format.
  401.          */
  402.         pfmt[0] = *fmt++;
  403.         n = 1;
  404.         while (strchr("-.0123456789", *fmt) != NULL) {
  405.         if (n < sizeof(pfmt)-2)
  406.             pfmt[n++] = *fmt;
  407.         ++fmt;
  408.         }
  409.         pfmt[n++] = 's';
  410.         pfmt[n] = '\0';
  411.  
  412.         /*
  413.          * Determine what we are printing.
  414.          */
  415.         if ((s = sel_alias_mem(ar, *fmt)) == NULL) {
  416.         s = catgets(elm_msg_cat, ElmaliasSet, ElmaliasIllegalFmtChar,
  417.             "<illegal format char>");
  418.         }
  419.  
  420.         /*
  421.          * Print out the formatted field.
  422.          */
  423.         if (print_enab)
  424.         printf(pfmt, s);
  425.         break;
  426.  
  427.     /*
  428.      * Conditional printing.
  429.      */
  430.     case '?':
  431.         if (in_conditional) {
  432.         in_conditional = FALSE;
  433.         print_enab = TRUE;
  434.         } else {
  435.         in_conditional = TRUE;
  436.         s = sel_alias_mem(ar, *++fmt);
  437.         print_enab = (s != NULL && *s != '\0');
  438.         }
  439.         break;
  440.     
  441.     /*
  442.      * Backslash escapes.
  443.      */
  444.     case '\\':
  445.         switch (*++fmt) {
  446.         case 'b':  c = '\b'; break;
  447.         case 'f':  c = '\f'; break;
  448.         case 'n':  c = '\n'; break;
  449.         case 'r':  c = '\r'; break;
  450.         case 't':  c = '\t'; break;
  451.         default:   c = *fmt; break;
  452.         }
  453.         if (print_enab && c != '\0')
  454.         putchar(c);
  455.         break;
  456.  
  457.     /*
  458.      * Non-special character to print.
  459.      */
  460.     default:
  461.         if (print_enab)
  462.         putchar(*fmt);
  463.         break;
  464.  
  465.     }
  466.  
  467.     if (*fmt != '\0')
  468.         ++fmt;
  469.  
  470.     }
  471.  
  472.     putchar('\n');
  473. }
  474.  
  475.  
  476. /*
  477.  * Select a member of the alias record structure.
  478.  */
  479. char *sel_alias_mem(ar, sel)
  480. struct alias_rec *ar;
  481. int sel;
  482. {
  483.     switch (sel) {
  484.     case 'a':
  485.     return ar->alias;
  486.     case 'l':
  487.     return ar->last_name;
  488.     case 'n':
  489.     return ar->name;
  490.     case 'c':
  491.     return ar->comment;
  492.     case 'v':
  493.     return ar->address;
  494.     case 't':
  495.     switch (ar->type & (PERSON|GROUP)) {
  496.     case PERSON:
  497.         return catgets(elm_msg_cat, ElmaliasSet,
  498.         ElmaliasTypePerson, "Person");
  499.     case GROUP:
  500.         return catgets(elm_msg_cat, ElmaliasSet,
  501.         ElmaliasTypeGroup, "Group");
  502.     default:
  503.         return catgets(elm_msg_cat, ElmaliasSet,
  504.         ElmaliasTypeUnknown, "Unknown");
  505.     }
  506.     default:
  507.     return (char *) NULL;
  508.     }
  509.     /*NOTREACHED*/
  510. }
  511.  
  512.